package org.mentalsmash.tazio.transactions.management;

import java.util.List;
import java.util.Set;
import java.util.concurrent.Future;

import org.mentalsmash.tazio.commons.identifiers.OID;
import org.mentalsmash.tazio.transactions.RollbackException;
import org.mentalsmash.tazio.transactions.Transaction;
import org.mentalsmash.tazio.transactions.TransactionStatus;
import org.mentalsmash.tazio.transactions.TransactionalSystemException;
import org.mentalsmash.tazio.transactions.identifiers.TID;
import org.mentalsmash.tazio.transactions.objects.Snapshot;
import org.mentalsmash.tazio.transactions.objects.TransactionalObject;

public interface TazioTransaction extends Transaction {

    /**
     * Registers an object that will be notified of status changes of this
     * <tt>TazioTransaction</tt> object
     * 
     * @param observer
     *            the observer object
     */
    void registerStateObserver(TxStateObserver observer);

    /**
     * Removes a previously registered state observer
     * 
     * @param observer
     *            the observer to remove
     * @return <code>true</code> if the observer was actually removed
     */
    boolean removeStateObserver(TxStateObserver observer);

    /**
     * Returns the transaction identifier of this transaction
     * 
     * @return the transaction identifier of this transaction
     */
    TID getTransactionId();

    /**
     * Returns the current sequence number of this transaction.
     * <p>
     * Notice that the sequence number of a transaction may change during a
     * transaction's lifespan
     * </p>
     * 
     * @return
     */
    long getSeqNo();

    TransactionStatus getStatus();

    /**
     * Checks whether the transaction is active or not.
     * <p>
     * A transaction is said to be active when it is status is <strong>
     * NONE</strong> of the following:
     * <ul>
     * <li>NO_TRANSACTION</li>
     * <li>COMMITTED</li>
     * <li>ROLLED_BACK</li>
     * </ul>
     * </p>
     * 
     * @return
     */
    boolean isActive();

    /**
     * Returns an unmodifiable View of the Read Set of this transaction
     * 
     * @return an unmodifiable View of the Read Set of this transaction
     */
    Set<OID> getReadSet();

    /**
     * Returns an unmodifiable View of the Write Set of this transaction
     * 
     * @return an unmodifiable View of the Write Set of this transaction
     */
    Set<OID> getWriteSet();

    void commit() throws RollbackException, TransactionStateException,
	    TransactionalSystemException;

    void rollback() throws TransactionStateException;

    void setRollbackOnly();

    Future<TransactionStatus> commitAsync() throws TransactionStateException;

    /**
     * Sets the sequence number of this transaction to the given value
     * 
     * @param seqNo
     *            the new sequece number
     * @throws IllegalSeqNoException
     *             if the provided sequence number is negative
     */
    void setSeqNo(long seqNo);

    /**
     * Changes the state of the <tt>TazioTransaction</tt> to the given
     * {@link TransactionStatus} and notifies the registered
     * {@link TxStateObserver}s
     * 
     * @param to
     *            the destination status to switch to
     */
    void stateTransition(TransactionStatus to);

    /**
     * Adds an oid to the write set, indicating that the corresponding object
     * was written in the context of this transaction
     * 
     * @param oid
     *            the {@link OID} of the object to add
     */
    void addToWriteSet(OID oid);

    /**
     * Adds an oid to the read set, indicating that the corresponding object was
     * read in the context of this transaction
     * 
     * @param oid
     *            the {@link OID} of the object to add
     */
    void addToReadSet(OID oid);

    /**
     * Returns the private snapshot for a transactional object, or
     * <code>null</code> if there is no snapshot for such an object
     * 
     * @param objectId
     *            the {@link OID} instance identifying a transactional object
     * @return a private snapshot of the object identified by
     *         <code>objectId</code> or <code>null</cod> if no such an object
     */
    Snapshot retrieveSnapshot(OID objectId);

    /**
     * Returns the list of operations performed by this transaction on a given
     * transactional object (empty if no operation was performed
     * on the given object).
     * 
     * @return the list of operations performed by this transaction on a given
     *         transactional object (empty if no operation was
     *         performed on the given object)
     */
    List<TransactionalOperation> getOperations(OID objectId);
    
    /**
     * returns the list of every write operation performed by this transaction.
     * <p>
     * Changing this map, <strong>does affect<strong> the state of the
     * transaction.
     * </p>
     * 
     * @return
     */
    List<TransactionalOperation> getWriteOperations();
    
    /**
     * returns the list of every read operation performed by this transaction.
     * <p>
     * Changing this map, <strong>does affect<strong> the state of the
     * transaction.
     * </p>
     * 
     * @return
     */ 
    List<TransactionalOperation> getReadOperations();

    /**
     * Log an operation on the transaction
     * 
     * @param op
     *            the operation instance to log
     */
    void logOperation(TransactionalOperation op);

    /**
     * Takes a snapshot of the given {@link TransactionalObject} and adds it to
     * the private snapshots of this transaction
     * 
     * @param obj
     *            the {@link TransactionalObject} instance to take the snapshot
     *            of
     */
    void takeSnapshot(TransactionalObject obj);

    /**
     * Checks whether rollback is set to be the only possible outcome of this
     * transaction
     * 
     * @return <code>true</code> if this transaction has to rollback no matter
     *         what
     */
    boolean isRollbackOnly();

}